#include "collisionshapes.h"
#include "../gameobjects/abstractobject.h"
#include "collisionshapesdocument.h"
#include <QPainter>
#include <math.h>

CollisionShape::CollisionShape()
    : m_type(Unknown)
    , m_fFriction(0.0f)
    , m_fRestitution(0.0f)
    , m_fDensity(1.0f)
{
}

CollisionShape::Type CollisionShape::type() const
{
    Q_ASSERT(m_type != Unknown);
    return m_type;
}

void CollisionShape::setPhysicsParams(float friction, float restitution, float density)
{
    m_fFriction = friction;
    m_fRestitution = restitution;
    m_fDensity = density;
}

void CollisionShape::physicsParams(float &friction, float &restitution, float &density)
{
    friction = m_fFriction;
    restitution = m_fRestitution;
    density = m_fDensity;
}

void CollisionShape::setShapeOwner(QPointer<AbstractObject> owner)
{
    m_shapeOwner = owner;
}


void CollisionShape::draw(QPointer<CollisionShapesDocument> csDoc, QPainter &painter) const
{
    if(csDoc->isSelected(const_cast<CollisionShape*>(this)))
    {
        painter.setPen(QPen(Qt::yellow, 1, Qt::DotLine));
        painter.setBrush(Qt::NoBrush);
        painter.drawRect(rect().adjusted(-4, -4, 4, 4));
    }
}

// CollisionBox

CollisionBox::CollisionBox(const QRectF &rect)
    : m_boxRect(rect)
{
    m_type = Rectangle;
}

void CollisionBox::draw(QPointer<CollisionShapesDocument> csDoc, QPainter &painter) const
{
    CollisionShape::draw(csDoc, painter);

    QPen pen(QColor(93, 207, 240), 1);
    drawRect(painter, m_boxRect, pen);
}

void CollisionBox::drawRect(QPainter &painter, const QRectF& rect, const QPen &pen)
{
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(pen);
    painter.drawRect(rect);
    painter.setRenderHint(QPainter::Antialiasing, false);
}

QRectF CollisionBox::rect() const
{
    return m_boxRect;
}

QPainterPath CollisionBox::shape() const
{
    QPainterPath path;
    path.addRect(m_boxRect);
    return path;
}

QList<QPointer<CollisionPoly> > CollisionBox::toPolygon(QPointer<CollisionShapesDocument> csDoc, int numIterations) const
{
    QList<QPointer<CollisionPoly> > result;

    QPolygonF poly[2];

    poly[0] << m_boxRect.bottomLeft();
    poly[0] << m_boxRect.topRight();
    poly[0] << m_boxRect.topLeft();

    poly[1] << m_boxRect.bottomRight();
    poly[1] << m_boxRect.topRight();
    poly[1] << m_boxRect.bottomLeft();

    csDoc->deleteShape(const_cast<CollisionBox*>(this));

    result << qobject_cast<CollisionPoly*>(csDoc->createPolyShape(poly[0]));
    result << qobject_cast<CollisionPoly*>(csDoc->createPolyShape(poly[1]));

    csDoc->deselectAllShapes();

    return result;
}

void CollisionBox::setBoxRect(const QRectF &rect)
{
    m_boxRect = rect;
    emit shapeChanged();
}

//  CollisionCircle

CollisionCircle::CollisionCircle(QPointF center, float radius)
    : m_center(center)
    , m_fRadius(radius)
{
    m_type = Circle;
}

void CollisionCircle::draw(QPointer<CollisionShapesDocument> csDoc, QPainter &painter) const
{
    CollisionShape::draw(csDoc, painter);

    QPen pen(QColor(93, 207, 240), 1);
    drawCircle(painter, m_center, m_fRadius, pen);
}

void CollisionCircle::drawCircle(QPainter &painter, const QPointF &center, float radius, const QPen& pen)
{
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(pen);
    painter.drawEllipse(center, radius, radius);
    painter.setRenderHint(QPainter::Antialiasing, false);
}

QRectF CollisionCircle::rect() const
{
    return QRectF(m_center.x() - m_fRadius, m_center.y() - m_fRadius,
                  m_fRadius*2, m_fRadius*2);
}

QPainterPath CollisionCircle::shape() const
{
    QPainterPath path;
    path.addEllipse(m_center, m_fRadius, m_fRadius);
    return path;
}

void CollisionCircle::setCenter(float x, float y)
{
    m_center = QPointF(x, y);
    emit shapeChanged();
}

void CollisionCircle::setRadius(float r)
{
    m_fRadius = r;
    emit shapeChanged();
}

QList<QPointer<CollisionPoly> > CollisionCircle::toPolygon(QPointer<CollisionShapesDocument> csDoc, int numIterations) const
{
    QList<QPointer<CollisionPoly> > result;

    QList<QPolygonF> polyList;

    int numVertices = numIterations*4;
    float angleInc = 2*3.14f/numVertices;

    for(int i=0;i<numVertices - 1;i++)
    {
        QPointF pt1;
        QPointF pt2;

        pt1.setX(m_center.x() + m_fRadius*cos((i + 1)*angleInc));
        pt1.setY(m_center.y() + m_fRadius*sin((i + 1)*angleInc));

        pt2.setX(m_center.x() + m_fRadius*cos(i*angleInc));
        pt2.setY(m_center.y() + m_fRadius*sin(i*angleInc));

        QPolygonF poly;
        poly << m_center;
        poly << pt1;
        poly << pt2;

        polyList << poly;
    }

    QPointF closingPt1;
    QPointF closingPt2;

    closingPt1.setX(m_center.x() + m_fRadius*cos(0.0f*angleInc));
    closingPt1.setY(m_center.y() + m_fRadius*sin(0.0f*angleInc));

    closingPt2.setX(m_center.x() + m_fRadius*cos((numVertices - 1)*angleInc));
    closingPt2.setY(m_center.y() + m_fRadius*sin((numVertices - 1)*angleInc));

    QPolygonF closingPoly;
    closingPoly << m_center;
    closingPoly << closingPt1;
    closingPoly << closingPt2;

    polyList << closingPoly;

    csDoc->deleteShape(const_cast<CollisionCircle*>(this));

    foreach(QPolygonF poly, polyList)
    {
        result << qobject_cast<CollisionPoly*>(csDoc->createPolyShape(poly));
    }

    csDoc->deselectAllShapes();

    return result;
}

// CollisionPoly
CollisionPoly::CollisionPoly(const QPolygonF &poly)
    : m_poly(poly)
{
    m_type = Polygon;
}


void CollisionPoly::draw(QPointer<CollisionShapesDocument> csDoc, QPainter &painter) const
{
    CollisionShape::draw(csDoc, painter);

    QPen pen(QColor(93, 207, 240), 1);
    drawPoly(painter, m_poly, pen);
}

void CollisionPoly::drawPoly(QPainter &painter, const QPolygonF &poly, const QPen &pen)
{
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(pen);
    painter.drawPolygon(poly);
    painter.setRenderHint(QPainter::Antialiasing, false);
}

QRectF CollisionPoly::rect() const
{
    QPainterPath path;
    path.addPolygon(m_poly);

    return path.boundingRect();
}

QPainterPath CollisionPoly::shape() const
{
    QPainterPath path;
    path.addPolygon(m_poly);
    return path;
}

void CollisionPoly::setPoly(const QPolygonF &poly)
{
    m_poly = poly;
    emit shapeChanged();
}

QList<QPointer<CollisionPoly> > CollisionPoly::toPolygon(QPointer<CollisionShapesDocument> csDoc, int numIterations) const
{
    Q_ASSERT(false);
    return QList<QPointer<CollisionPoly> >();
}
